/**
 * Copyright (C) 2016 Robinhood Markets, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.robinhood.os_spark;


import ohos.agp.components.Component;
import ohos.eventhandler.EventHandler;
import ohos.multimodalinput.event.MmiPoint;
import ohos.multimodalinput.event.TouchEvent;

/**
 * Exposes simple methods for detecting scrub events.
 */
class ScrubGestureDetector implements Component.TouchEventListener {
    static final long LONG_PRESS_TIMEOUT_MS = 250;

    private final ScrubListener scrubListener;
    private final float touchSlop;
    private final EventHandler handler;

    private boolean enabled;
    private float downX, downY;

    ScrubGestureDetector(
            ScrubListener scrubListener,
            EventHandler handler,
            float touchSlop) {
        this.scrubListener = scrubListener;
        this.handler = handler;
        this.touchSlop = touchSlop;
    }



    private final Runnable longPressRunnable = new Runnable() {
        @Override
        public void run() {
            scrubListener.onScrubbed(downX, downY);
        }
    };

    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }


    @Override
    public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
        if (!enabled) return false;

        MmiPoint pointerPosition = touchEvent.getPointerPosition(touchEvent.getIndex());
        final float x = pointerPosition.getX();
        final float y = pointerPosition.getY();
        switch (touchEvent.getAction()) {
            case TouchEvent.PRIMARY_POINT_DOWN:
                // store the time to compute whether future events are 'long presses'
                downX = x;
                downY = y;

                handler.postTask(longPressRunnable, LONG_PRESS_TIMEOUT_MS);
                return true;
            case TouchEvent.POINT_MOVE:
                // calculate the elapsed time since the down event
                float timeDelta = touchEvent.getOccurredTime() - touchEvent.getStartTime();

                // if the user has intentionally long-pressed
                if (timeDelta >= LONG_PRESS_TIMEOUT_MS) {
                    handler.removeTask(longPressRunnable);
                    scrubListener.onScrubbed(x, y);
                } else {
                    // if we moved before longpress, remove the callback if we exceeded the tap slop
                    float deltaX = (float) ((double)x - (double)downX);
                    float deltaY = (float) ((double)y - (double)downY);
                    if (deltaX >= touchSlop || deltaY >= touchSlop) {
                        handler.removeTask(longPressRunnable);
                        // We got a MOVE event that exceeded tap slop but before the long-press
                        // threshold, we don't care about this series of events anymore.
                        return false;
                    }
                }

                return true;
            case TouchEvent.PRIMARY_POINT_UP:
            case TouchEvent.CANCEL:
                handler.removeTask(longPressRunnable);
                scrubListener.onScrubEnded();
                return true;
            default:
                return false;
        }
    }

    interface ScrubListener {
        void onScrubbed(float x, float y);
        void onScrubEnded();
    }
}

